package com.ruoyi.iot.rabbitmq;

import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import com.ruoyi.iot.channel.SynchroniseMessage;
import com.ruoyi.iot.channel.device.DeviceMessageServiceImpl;
import com.ruoyi.iot.channel.translator.impl.TransformServiceImpl;
import com.ruoyi.iot.domain.dto.ExchangeDTO;
import com.ruoyi.iot.domain.vo.enums.EPlatformCmdType;
import com.ruoyi.iot.domain.vo.enums.ESponsor;
import com.ruoyi.iot.domain.vo.DevCmdVo;
import com.ruoyi.iot.domain.*;
import com.ruoyi.iot.exchange.network.tcp.cache.TcpChannelCache;
import com.ruoyi.iot.service.impl.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.xmlbeans.impl.util.HexBin;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * 服务调用的总入口
 */
@Component
@Slf4j
public class ExchangeRabbitHelper  {

    /**
     * 设备信息处理器
     */
    @Autowired
    DeviceMessageServiceImpl deviceMessageService;

    /**
     * 设备信息服务
     */
    @Autowired
    IotDeviceServiceImpl iotDeviceService;

    /**
     * 产品信息服务
     */
    @Autowired
    IotProductServiceImpl iotProductService;

    /**
     * 指令服务
     */
    @Autowired
    IotCmdServiceImpl iotCmdService;



    /**
     * 同步消息服务
     */
    @Autowired
    SynchroniseMessage synchroniseMessage;

    /**
     * 消息转换服务
     */
    @Autowired
    TransformServiceImpl transformService;


    static ExchangeRabbitHelper exchangeRabbitHelper;

    public static ExchangeRabbitHelper getInstance(){
        return exchangeRabbitHelper;
    }

    @PostConstruct
    public void initFactory(){
        exchangeRabbitHelper = this;
    }


    @RabbitListener(queues = "${spring.rabbitmq.template.http-queue}")
    public void receiveWebChannel(Message message, Channel channel) throws Exception {
        String exchangeJson =new String(message.getBody());
        System.out.println("http-message:" + exchangeJson);
        ExchangeDTO exchangeDTO = JSON.parseObject(exchangeJson, ExchangeDTO.class);
        log.info("prepare notify web => " + exchangeDTO.toString());

        String devNum = exchangeDTO.getDevId();
        String cmdHex = exchangeDTO.getCmdHex();
        IotDevice iotDevice = iotDeviceService.selectIotDeviceByDevNum(devNum);
        Long productId = iotDevice.getProductId();

        IotCmd iotCmdCondition = new IotCmd();
        iotCmdCondition.setProductId(productId);
        iotCmdCondition.setSponsor(ESponsor.device.getValue());
        iotCmdCondition.setCmdHex(cmdHex);
        List<IotCmd> iotCmds = iotCmdService.selectIotCmdList(iotCmdCondition);
        log.info(String.format("find dev cmd size:%s!",iotCmds.size()));
        if(iotCmds.size() != 1) {
            log.info(String.format("dev:%s mysql config empty!",devNum));
            return;
        } else {
            IotCmd iotCmd =  iotCmds.get(0);
            EPlatformCmdType ePlatformCmdType = EPlatformCmdType.getType(iotCmd.getCmdType().intValue());

            switch (ePlatformCmdType){
                case CMD:{
                    deviceMessageService.deviceReport(exchangeDTO);
                    DevCmdVo devCmdVo = synchroniseMessage.waitCmdMessage(devNum,iotCmd.getResultId());
                    ExchangeDTO exchangeDTOResult = transformService.platTransform(devCmdVo);
                    //设备上报请求返回结果，取到数据后，走mq通道，返回到设备
                    webPublishToMQ(exchangeDTOResult);
                }
                break;
                case NOTICE: {
                    deviceMessageService.deviceReport(exchangeDTO);
                }
                    break;
                case RESULT:{
                    deviceMessageService.deviceResult(exchangeDTO);
                }
                    break;
                case NOTICE_OR_RESULT:{
                    Boolean isExist = synchroniseMessage.isExistBlockKey(devNum,iotCmd.getId());
                    if(isExist) {
                        deviceMessageService.deviceResult(exchangeDTO);
                    } else {
                        deviceMessageService.deviceReport(exchangeDTO);
                    }
                }
                    break;
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }


    @RabbitListener(queues = "${spring.rabbitmq.template.tcp-queue}")
    public void receiveTcpMessage(Message message, Channel channel) throws Exception {
        String exchangeJson =new String(message.getBody());
        ExchangeDTO exchangeDTO = JSON.parseObject(exchangeJson, ExchangeDTO.class);
        String recFormat = "devId:%s frame:%s";
        byte[] data = exchangeDTO.getData();
        String publishMsg = String.format(recFormat,exchangeDTO.getDevId(), HexBin.bytesToString(data));
        log.info("publish to device:" + publishMsg);

        ByteBuf buffer = Unpooled.copiedBuffer(data);

        ChannelHandlerContext nettyChannel = TcpChannelCache.getChannel(exchangeDTO.getDevId());
        if( nettyChannel != null) {
            nettyChannel.pipeline().writeAndFlush(buffer);
        } else {
            log.info("dev:%s offline",exchangeDTO.getDevId());
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }


    /**
     * rabbit发送消息
     */
    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * 发送信息到rabbitmq中处理
     * @param exchangeDTO
     */
    public void webPublishToMQ(ExchangeDTO exchangeDTO) {
         String webMQRoutKey =  exchangeDTO.getWebToMqRouteKey();
         String jsonStr = JSON.toJSONString(exchangeDTO);
         log.info(String.format("rabbit: RouteKey:%s  Message:%s",webMQRoutKey,jsonStr));

         rabbitTemplate.convertAndSend(webMQRoutKey,jsonStr.getBytes());
    }

    public void devPublishToMQ(ExchangeDTO exchangeDTO) {
        String devMQRouteKey = exchangeDTO.getDeviceToMqRouteKey();
        String jsonStr = JSON.toJSONString(exchangeDTO);
        log.info(String.format("devPublishMQ: RouteKey:%s  Message:%s",devMQRouteKey,jsonStr));
        rabbitTemplate.convertAndSend(devMQRouteKey,jsonStr.getBytes());
    }




}
